package bb.lanxing.mvp.presetner;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import bb.lanxing.model.database.Workout;
import bb.lanxing.mvp.model.WorkoutSyncModelImpl;
import bb.lanxing.mvp.model.i.IWorkoutSyncModel;
import bb.lanxing.mvp.model.i.ResultListener;
import bb.lanxing.mvp.presetner.i.IWorkoutSyncPresenter;
import bb.lanxing.service.SyncTaskService;
import bb.lanxing.util.Enums;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

public class WorkoutSyncPresenterImpl implements IWorkoutSyncPresenter {
    private SyncTaskService.SyncTask<Workout> syncTask;
    private IWorkoutSyncModel workoutSyncModel = new WorkoutSyncModelImpl();
    private List<Workout> uploadQueue = new LinkedList();
    private LinkedList<Workout> successQueue = new LinkedList<>();
    private LinkedList<Workout> failureQueue = new LinkedList<>();
    private ResultListener<Workout, Workout> listener = getListener();

    public WorkoutSyncPresenterImpl(SyncTaskService.SyncTask<Workout> vSyncTask) {
        this.syncTask = vSyncTask;
    }

    @Override
    public void syncWorkout(long workoutId) {
        Observable.just(workoutId).subscribeOn(Schedulers.io())
                .flatMap(workoutId2 -> Observable.just(Workout.getById(workoutId2)))
                .observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<>() {
                    @Override
                    public void onCompleted() {
                    }

                    @Override
                    public void onError(Throwable e) {
                        for (Workout workout : uploadQueue) {
                            if (!successQueue.contains(workout)) {
                                failureQueue.add(workout);
                            }
                        }
                        syncTask.onFinish(successQueue, failureQueue);
                    }

                    @Override
                    public void onNext(Workout workout) {
                        if (workout == null) {
                            syncTask.onFinish(successQueue, failureQueue);
                            return;
                        }
                        ArrayList<Workout> arrayList = new ArrayList<>(1);
                        if (workout.getUploadStatus() == Enums.UploadStatus.NotUpload) {
                            arrayList.add(workout);
                        }
                        uploadQueue.addAll(arrayList);
                        int locSource = workout.getLocSource();
                        if (locSource == Workout.LOCATION_SOURCE_OTHER
                                || locSource == Workout.LOCATION_SOURCE_NONE
                                || locSource == Workout.LOCATION_SOURCE_PHONE
                                || locSource == Workout.LOCATION_SOURCE_XOSS_NAV //to be deleted
                                || locSource == Workout.LOCATION_SOURCE_BES_WATCH) {
                            boolean result = workoutSyncModel.uploadJsonWorkout(arrayList, listener);
                            if (result) {
                                syncTask.onStart(uploadQueue);
                                return;
                            }
                        } else {
                            boolean result = workoutSyncModel.uploadFitWorkout(arrayList, listener);
                            if (result) {
                                syncTask.onStart(uploadQueue);
                                return;
                            }
                        }

                        failureQueue.addAll(arrayList);
                        syncTask.onFinish(successQueue, failureQueue);
                    }
                });
    }

    @Override
    public void syncWorkoutAll(long userId) {
        this.workoutSyncModel.getUnUploadWorkout(userId, new Subscriber<>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                for (Workout workout : uploadQueue) {
                    if (!successQueue.contains(workout)) {
                        failureQueue.add(workout);
                    }
                }
                syncTask.onFinish(successQueue, failureQueue);
            }

            @Override
            public void onNext(List<Workout> uploadWorkouts) {
                uploadQueue.addAll(uploadWorkouts);
                ArrayList<Workout> arrayList = new ArrayList<>();
                ArrayList<Workout> arrayList2 = new ArrayList<>();
                for (Workout workout : uploadWorkouts) {
                    int locSource = workout.getLocSource();
                    if (locSource == Workout.LOCATION_SOURCE_OTHER
                            || locSource == Workout.LOCATION_SOURCE_NONE
                            || locSource == Workout.LOCATION_SOURCE_PHONE
                            || locSource == Workout.LOCATION_SOURCE_XOSS_NAV //to be deleted
                            || locSource == Workout.LOCATION_SOURCE_BES_WATCH) {
                        arrayList.add(workout);
                    } else {
                        arrayList2.add(workout);
                    }
                }
                if (!workoutSyncModel.uploadJsonWorkout(arrayList, listener)) {
                    failureQueue.addAll(arrayList);
                }
                if (arrayList2.isEmpty()) {
                    return;
                }
                if (!workoutSyncModel.uploadFitWorkout(arrayList2, listener)) {
                    failureQueue.addAll(arrayList2);
                }
                syncTask.onStart(uploadWorkouts);
            }
        });
    }

    @Override
    public void release() {
        this.workoutSyncModel.cancelUpload();
        this.failureQueue.clear();
        for (int i = 0; i < this.uploadQueue.size(); i++) {
            Workout workout = this.uploadQueue.get(i);
            if (!this.successQueue.contains(workout)) {
                this.failureQueue.add(workout);
            }
        }
        this.syncTask.onFinish(this.successQueue, this.failureQueue);
    }

    private ResultListener<Workout, Workout> getListener() {
        return new ResultListener<>() {
            @Override
            public void onProgress(Workout target, long curr, long total) {
                if (successQueue.contains(target)) {
                    return;
                }
                HashMap<String, Object> hashMap = new HashMap<>();
                hashMap.put("workoutId", target.getId());//SyncTaskService.EXTRA_WORKOUT_ID
                hashMap.put("progress", (curr / total) * 100.0d);
                syncTask.onProgress(target, hashMap);
            }

            @Override
            public void onResult(Workout result) {
                if (successQueue.contains(result)) {
                    return;
                }
                successQueue.add(result);
                HashMap<String, Object> hashMap = new HashMap<>();
                hashMap.put("success", true);
                hashMap.put("workoutId", result.getId());//SyncTaskService.EXTRA_WORKOUT_ID
                hashMap.put("index", successQueue.size());//MapBundleKey.MapObjKey.OBJ_SL_INDEX
                hashMap.put("size", uploadQueue.size());
                syncTask.onUpdate(result, hashMap);
                checkIfFinished();
            }

            @Override
            public void onError(Workout input, Throwable e) {
                if (failureQueue.contains(input)) {
                    return;
                }
                HashMap<String, Object> hashMap = new HashMap<>();
                hashMap.put("success", false);
                hashMap.put("workoutId", input.getId());//SyncTaskService.EXTRA_WORKOUT_ID
                hashMap.put("error", e.getMessage());//d.O
                hashMap.put("index", successQueue.size());//MapBundleKey.MapObjKey.OBJ_SL_INDEX
                hashMap.put("size", uploadQueue.size());
                failureQueue.add(input);
                syncTask.onUpdate(input, hashMap);
                checkIfFinished();
            }
        };
    }

    public boolean checkIfFinished() {
        if (this.uploadQueue.size() <= this.successQueue.size() + this.failureQueue.size()) {
            this.syncTask.onFinish(this.successQueue, this.failureQueue);
            return true;
        }
        return false;
    }
}